#include "ultrasonic.h"

//gpio初始化
void gpio_init (void)
{	int i, j;
	for (i = 0; i < 6; i++) {
		gpio_val[i].group = i;
		for (j = 0; j < 16; j++) {
			gpio_val[i].num[j] = 496 - 16*i + j;
		}
	}
}

//获取gpio引脚编号
int get_gpio (struct gpio_desc gpios)
{
	return gpio_val[gpios.group].num[gpios.num[0]];
}

//写gpioxxx的属性文件（与congfig_gpio配合使用）
int write_gpio (char *pptr, char *attr, char *val )
{
	int fd;
	char file_path_val[128];
	sprintf (file_path_val, "%s/%s", pptr, attr);
	if (-1 == (fd = open (file_path_val, O_WRONLY))) {
		printf ("file_path_val open file!\n");
		return -1;
	}
	int len = strlen(val);
	if ( len != (write (fd, val, len))) {
		perror ("write val faile!\n");
		close (fd);
		return -1;
	}
	close (fd);
	return 0;
}
/*******************************************************
 功能：配置gpioxxx文件的属性
 参数：
 	group 组号（0-5）
	num   组内引脚号（0-15）
	buff  保存gpioxxx文件的value路径，如"/sys/class/gpio/gpioxxx/value"
*******************************************************/
int config_gpio (int group, int num, char *buff)
{
	gpios.group = group;
	gpios.num[0] = num;

	sprintf (gpio_num, "%d", get_gpio(gpios));
	sprintf (pptr, "/sys/class/gpio/gpio%s", gpio_num);
	
	if (access (pptr, F_OK)) {
		int fd;
		if (0 > (fd = open ("/sys/class/gpio/export", O_WRONLY))) {
				perror ("file open file!");
				return -1;
		}
		int len = sizeof(gpio_num);
		if ( len != (write (fd, gpio_num, len))) {
				perror ("write gpio_num faile!");
				close (fd);
				return -1;
		}	
		close (fd);
	}
	if (gpios.group == 4 && gpios.num[0] == 4) {
		if (-1 == (write_gpio (pptr, "edge", "none"))) {
				perror ("write_gpio4_4 run faile");
				return -1;
		}
		if (-1 == (write_gpio (pptr, "direction", "out"))) {
				perror ("write_gpio4_5 run faile");
				return -1;
		}
	} else if (gpios.group == 4 && gpios.num[0] == 5){
		if (-1 == (write_gpio (pptr, "edge", "both"))) {
			perror ("write_gpio run faile");
			return -1;
		}
		if (-1 == (write_gpio (pptr, "direction", "in"))) {
				perror ("write_gpio run faile");
				return -1;
		}	
	} else if ((gpios.group == 4 && gpios.num[0] == 1) || (gpios.group == 4 && gpios.num[0] == 3)) {
		//配置按键
		//配置节点文件下的属性文件edge和direction
		//both:中断模式
		if (-1 == write_gpio (pptr, "edge", "falling")) {
			perror ("write_gpio_key edge run faile");
			return -1;
		}
		//in：输入模式
		if (-1 == write_gpio (pptr, "direction", "in")) {
			perror ("write_gpio_key direction run faile");
			return -1;
		}
	} else {
		//配置步进电机
		//配置节点文件下的属性文件edge和direction
		//none:非中断模式
		if (-1 == write_gpio (pptr, "edge", "none")) {
			perror ("write_gpio_motor edge run faile");
			return -1;
		}
		//out：输出模式
		if (-1 == write_gpio (pptr, "direction", "out")) {
			perror ("write_gpio_motor direction run faile");
			return -1;
		}
	}
	memset (buff, 0, BUFFSIZE/sizeof(char));
	sprintf (buff, "%s/%s", pptr, "value");
	return 0;
}
void set_gpio_out (char *buff, char *value)
{
	int fd;
	int len;
	char file_path[128];
	sprintf (file_path, "%s", buff);
	if (-1 == (fd = open (file_path, O_WRONLY))) {
		perror ("gpio_out_value open faile");
		exit (-1);
	}
	len = strlen (value);
	if (len != write (fd, value, len)) {
		perror ("gpio_out_value write faile");
		close (fd);
		exit (-1);
	}
	close (fd);
}
int get_diatance_value (void)
{
	struct pollfd fds[1];
	char buf[128] = {0};
	int ret = 0;
	struct timespec tc, tf;
	float distance = 0;
	int fd;

	//buff4_5:"/sys/class/gpio4_5/value"
	fd = open (buff4_5, O_RDONLY);
	if (fd == - 1) {
		perror ("value_fd open faile");
		exit (-1);
	}

	fds[0].fd = fd;
	fds[0].events = POLLPRI;

	ret = read (fd, buf, 10);
	if (ret == -1) {
		perror ("read value_fd error");
		exit(-1);
	}
	
	while (10) {
		ret = poll (fds, 1, -1);
		printf("test2\n");
		if (-1 == ret) {
			perror ("poll error");
			exit(-1);
		}
		//value值发生变化(中断来临)
		
		if (fds[0].revents & POLLPRI) {
			//定位文件指针到文件的开头，方便读取
			ret = lseek (fd, 0, SEEK_SET);
			if (-1 == ret) {
				perror ("lseek error");
			}
			
			memset (buf, 0, BUFFSIZE/sizeof(char));
			
			//读取fd文件（value）中的值保存到buf中，buf的值应该是1（高电平）
			ret  = read (fd, buf, 1);
			printf ("test3\n");
			if (ret == -1) {
				perror ("read error");
			}
			if (atoi(buf) == 1) {
				//开始计时
				clock_gettime (CLOCK_REALTIME, &tc);
			} else if (atoi(buf) == 0) {
				clock_gettime	(CLOCK_REALTIME, &tf);
				distance = (tf.tv_nsec - tc.tv_nsec)/1000 / 29.4 / 2;
				if (distance > 0) {
					//printf ("distance: %.2fcm\n", distance);
					return (int)distance;
				}
				close (fd);
				break;
			}
		}
	}
}
//发射超声波（与get_diatance_value配合使用）
void send_ultrasonic (void)
{
	struct timespec ts, tc;
	set_gpio_out (buff4_4, "1");
	//10us延时
	clock_gettime (CLOCK_REALTIME, &ts);
	while ((tc.tv_nsec - ts.tv_nsec)/1000 <= 10) {
		for (int i = 0; i < 5; i++);//减轻CPU负担
		clock_gettime (CLOCK_REALTIME, &tc);
	}
	set_gpio_out (buff4_4, "0");
}
